/**
 * @brief 串口驱动
 * @author 张勇 41204@qq.com
 * @date 2022-04
*/

#include <string.h>
#include <stm32f10x_gpio.h>

#include "share/cccompat.h"
#include "share/console.h"
//#include "share/ymodem.h"
#include "share/unios.h"
#include "_mcu.h"
#include "_mcu_gpio.h"
#include "_mcu_uart.h"

// 串口时钟使能并复位(波特率等参数只有复位之后才能重新设置)
static std_err_t _uart_reset(USART_TypeDef* port) {
	/**/ if(port == USART1) { RCC_PeriphResetCmd_USART1(ENABLE); RCC_PeriphResetCmd_USART1(DISABLE); }
	else if(port == USART2) { RCC_PeriphResetCmd_USART2(ENABLE); RCC_PeriphResetCmd_USART2(DISABLE); }
	else if(port == USART3) { RCC_PeriphResetCmd_USART3(ENABLE); RCC_PeriphResetCmd_USART3(DISABLE); }
	else if(port == UART4 ) { RCC_PeriphResetCmd_UART4(ENABLE);  RCC_PeriphResetCmd_UART4(DISABLE);  }
	else if(port == UART5 ) { RCC_PeriphResetCmd_UART5(ENABLE);  RCC_PeriphResetCmd_UART5(DISABLE);  }
    else return STD_ERR_INVALID_ARG;
    return STD_ERR_OK;
}

IRQn_Type mcu_uart_irqn(mcu_uart_t *dev) {
    /**/ if(dev->port == USART1) return USART1_IRQn;
    else if(dev->port == USART2) return USART2_IRQn;
    else if(dev->port == USART3) return USART3_IRQn;
    else if(dev->port == UART4 ) return UART4_IRQn ;
    else if(dev->port == UART5 ) return UART5_IRQn ;
    else return USART1_IRQn;
}

// 初始化 UART 使用的 GPIO 引脚
static std_err_t _uart_init_gpio(USART_TypeDef* port, mcu_gpio_num_t _txpin, mcu_gpio_num_t _rxpin) {
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_TypeDef *txport = NULL, *rxport = NULL;
    uint32_t txpin, rxpin;
    
    // 检查 _rxpin 是否是指定的引脚，如果不是就返回错误
    #define CHECK_RX_PIN(PIN)   if(_rxpin != MCU_GPIO_NUM_##PIN) return STD_ERR_INVALID_ARG;

    if(port == USART1) switch(_txpin) {
        case MCU_GPIO_NUM_PA9:  { CHECK_RX_PIN(PA10); txport = GPIOA; txpin = GPIO_Pin_9 ; rxport = GPIOA; rxpin = GPIO_Pin_10; break; }
        case MCU_GPIO_NUM_PB6:  { CHECK_RX_PIN(PB7 ); txport = GPIOB; txpin = GPIO_Pin_6 ; rxport = GPIOB; rxpin = GPIO_Pin_7 ; GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE); break; }
        default: return STD_ERR_INVALID_ARG;                           
    }
    else if(port == USART2) switch(_txpin) {
        case MCU_GPIO_NUM_PA2:  { CHECK_RX_PIN(PA3 ); txport = GPIOA; txpin = GPIO_Pin_2 ; rxport = GPIOA; rxpin = GPIO_Pin_3 ; break; }
        case MCU_GPIO_NUM_PD5:  { CHECK_RX_PIN(PD6 ); txport = GPIOD; txpin = GPIO_Pin_5 ; rxport = GPIOD; rxpin = GPIO_Pin_6 ; GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); break; }
        default: return STD_ERR_INVALID_ARG;                          
    }
    else if(port == USART3) switch(_txpin) {
        case MCU_GPIO_NUM_PB10: { CHECK_RX_PIN(PB11); txport = GPIOB; txpin = GPIO_Pin_10; rxport = GPIOB; rxpin = GPIO_Pin_11; break; }
        case MCU_GPIO_NUM_PC10: { CHECK_RX_PIN(PC11); txport = GPIOC; txpin = GPIO_Pin_10; rxport = GPIOC; rxpin = GPIO_Pin_11; GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE); break; }
        case MCU_GPIO_NUM_PD8 : { CHECK_RX_PIN(PD9 ); txport = GPIOD; txpin = GPIO_Pin_8 ; txport = GPIOD; txpin = GPIO_Pin_9 ; GPIO_PinRemapConfig(GPIO_FullRemap_USART3   , ENABLE); break; }
        default: return STD_ERR_INVALID_ARG;                           
    }
    else if(port == UART4) switch(_txpin) {
        case MCU_GPIO_NUM_PC10: { CHECK_RX_PIN(PC11); txport = GPIOC; txpin = GPIO_Pin_10; rxport = GPIOC; rxpin = GPIO_Pin_11; break; }
        default: return STD_ERR_INVALID_ARG;                           
    }
    else if(port == UART5) switch(_txpin) {
        case MCU_GPIO_NUM_PC12: { CHECK_RX_PIN(PD2); txport = GPIOC; txpin = GPIO_Pin_12; rxport = GPIOD; rxpin = GPIO_Pin_2 ; break; }
        default: return STD_ERR_INVALID_ARG;                           
    }
    else return STD_ERR_INVALID_ARG;
    
    // 配置 USART1 TX (PA9) 为复用推挽输出
    GPIO_InitStruct.GPIO_Pin = txpin;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;  // 复用推挽输出
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(txport, &GPIO_InitStruct);

    // 配置 USART1 RX (PA10) 为浮空输入
    GPIO_InitStruct.GPIO_Pin = rxpin;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;  // 浮空输入
    GPIO_Init(rxport, &GPIO_InitStruct);

    return STD_ERR_OK;
}

std_err_t mcu_uart_init(mcu_uart_t *dev, mcu_gpio_num_t txpin, mcu_gpio_num_t rxpin, uint32_t baudrate, mcu_uart_databits_t databits, mcu_uart_stopbits_t stopbits, mcu_uart_parity_t parity) {
    if(!dev || !dev->port) { return STD_ERR_INVALID_ARG; }
    std_err_t err;

    // 初始化 UART 使用的 GPIO 引脚
    err = _uart_init_gpio(dev->port, txpin, rxpin); if(err) return err;

    // 串口复位(波特率等参数只有复位之后才能重新设置)
    err = _uart_reset(dev->port); if(err) return err;

    // 配置USART参数
	USART_InitTypeDef init;
	USART_StructInit(&init);
	init.USART_BaudRate              = baudrate;
	init.USART_Mode                  = USART_Mode_Rx | USART_Mode_Tx;
	init.USART_HardwareFlowControl   = USART_HardwareFlowControl_None;
    switch(databits) {
        case MCU_UART_DATABITS_8: init.USART_WordLength = USART_WordLength_8b; break;
        case MCU_UART_DATABITS_9: init.USART_WordLength = USART_WordLength_9b; break;
        default: return STD_ERR_NOT_SUPPORTED;
    }
    switch(stopbits) {
        case MCU_UART_STOPBITS_0_5: init.USART_StopBits = USART_StopBits_0_5; break;
        case MCU_UART_STOPBITS_1  : init.USART_StopBits = USART_StopBits_1  ; break;
        case MCU_UART_STOPBITS_1_5: init.USART_StopBits = USART_StopBits_1_5; break;
        case MCU_UART_STOPBITS_2  : init.USART_StopBits = USART_StopBits_2  ; break;
        default: return STD_ERR_NOT_SUPPORTED;
    }
    switch(parity) {
        case MCU_UART_PARITY_NO:   init.USART_Parity = USART_Parity_No;   break;
        case MCU_UART_PARITY_EVEN: init.USART_Parity = USART_Parity_Even; break;
        case MCU_UART_PARITY_ODD:  init.USART_Parity = USART_Parity_Odd ; break;
        default: return STD_ERR_NOT_SUPPORTED;
    }
	USART_Init(dev->port, &init);
	
    // 启用 USART
	USART_Cmd(dev->port, ENABLE);
	
	return STD_ERR_OK;
}

std_err_t mcu_uart_set_rxbyte_callback(mcu_uart_t* dev, func_uart_rxbyte_t rxbyte_callback, void *rxbyte_cookie) {
    if(!dev || !rxbyte_callback) return STD_ERR_INVALID_ARG;
    dev->rxhandler = rxbyte_callback; dev->rxcookie = rxbyte_cookie;
    return STD_ERR_OK;
}

/// @brief 设置 UART 回调函数: 发送缓冲区空
std_err_t mcu_uart_set_txempty_callback(mcu_uart_t* dev, func_uart_txempty_t txempty_callback, void *txempty_cookie) {
    if(!dev || !txempty_callback) return STD_ERR_INVALID_ARG;
    dev->txhandler = txempty_callback; dev->txcookie = txempty_cookie;
    return STD_ERR_OK;
}

/*
USART_FLAG_xxx/USART_IT_xxx:
   CTS:  CTS Change flag (not available for UART4 and UART5)
   LBD:  LIN Break detection flag
   TXE:  Transmit data register empty flag
   TC:   Transmission Complete flag
   RXNE: Receive data register not empty flag
   IDLE: Idle Line detection flag
   ORE:  OverRun Error flag
   NE:   Noise Error flag
   FE:   Framing Error flag
   PE:   Parity Error flag

 - IDLE, ORE, NE, FE, PE 中断清除方法：
   USART_GetITStatus()
   USART_ReceiveData()
*/

/// @brief 统一中断处理入口
_RAMCODE_ void mcu_uart_irq_handler(mcu_uart_t* dev) {
    if(!dev || !dev->port) return;
    USART_TypeDef* uart = dev->port;

    // 判断是否有接收中断
    __IO uint32_t SR = uart->SR;
    __IO uint8_t ch = (uart->DR & 0xFF);

    if( (SR & USART_FLAG_PE) || (SR & USART_FLAG_FE) || (SR & USART_FLAG_NE) ) {
        // 数据错误，丢弃
		return;
	}

	if( (SR & USART_FLAG_ORE) || (SR & USART_FLAG_IDLE) ) {
		// 数据有效，继续
	}

	if(SR & USART_IT_RXNE) {
		if(dev->rxhandler) { 
			// 回调字符接收函数
			dev->rxhandler(dev, dev->rxcookie, ch); 
		}
	}
		
	// 判断是否有发送中断
	if(USART_GetITStatus(uart, USART_IT_TC) || USART_GetITStatus(uart, USART_IT_TXE)) {
		if(dev->txhandler) {
			// 调用发送完成中断回调
			dev->txhandler(dev, dev->txcookie);
		} else {
			// 如果没人管，则必须将 TXE 中断关闭，否则会不断地产生中断，导致系统 down 机
			mcu_uart_tx_irq_enable(dev, false);
		}

		USART_ClearITPendingBit(uart, USART_IT_TC);
		USART_ClearITPendingBit(uart, USART_IT_TXE);
		return;
	}
}

std_err_t mcu_uart_rx_irq_enable(mcu_uart_t* dev, bool sw) {
    if(!dev || !dev->port) { return STD_ERR_INVALID_ARG; }
	
    if(sw) {
		// 启用接收数据中断
		USART_ITConfig(dev->port, USART_IT_RXNE, ENABLE);
		USART_ITConfig(dev->port, USART_IT_ORE,  ENABLE);
		// 禁用其它中断
		USART_ITConfig(dev->port, USART_IT_IDLE, DISABLE);
		USART_ITConfig(dev->port, USART_IT_PE, 	DISABLE);
		USART_ITConfig(dev->port, USART_IT_ERR, 	DISABLE);
		USART_ITConfig(dev->port, USART_IT_NE, 	DISABLE);
		USART_ITConfig(dev->port, USART_IT_FE, 	DISABLE);
        mcu_intc_enable(mcu_intc(), mcu_uart_irqn(dev), true);
    } else {
        //mcu_intc_enable(mcu_intc(), mcu_uart_irqn(dev), false);
		USART_ITConfig(dev->port, USART_IT_RXNE, DISABLE);
		USART_ITConfig(dev->port, USART_IT_ORE,  DISABLE);
    }
	
	return STD_ERR_OK;
}

std_err_t mcu_uart_tx_irq_enable(mcu_uart_t* dev, bool sw) {
	if(!dev || !dev->port) { return STD_ERR_INVALID_ARG; }
	
    if(sw) {
		USART_ITConfig(dev->port, USART_IT_TC, ENABLE);
		USART_ITConfig(dev->port, USART_IT_TXE, ENABLE);
        mcu_intc_enable(mcu_intc(), mcu_uart_irqn(dev), true);
    } else {
        //mcu_intc_enable(mcu_intc(), mcu_uart_irqn(dev), false);
		USART_ITConfig(dev->port, USART_IT_TC, DISABLE);
		USART_ITConfig(dev->port, USART_IT_TXE, DISABLE);
    }
	
	return STD_ERR_OK;
}

std_err_t mcu_uart_clear_rxfifo(mcu_uart_t* dev) {
	// STM32F4 USART 没有 FIFO
    return STD_ERR_OK;
}

std_err_t mcu_uart_clear_txfifo(mcu_uart_t* dev) {
	// STM32F1 USART 没有 FIFO
    return STD_ERR_OK;
}

/// 单字符输出
std_err_t mcu_uart_putc(mcu_uart_t* dev, uint8_t ch) {
    if(!dev || !dev->port) { return STD_ERR_INVALID_ARG; }
    // 等待发送缓冲区为空
	while(!USART_GetFlagStatus(dev->port, USART_FLAG_TXE));
    // 发送数据
	USART_SendData(dev->port, ch);
	return STD_ERR_OK;
}

/// 字符输入
std_err_t mcu_uart_getc(mcu_uart_t *dev, uint8_t *ch) {
	if(!dev || !dev->port || !ch) { return STD_ERR_INVALID_ARG; }
    // 如果接收缓冲区中没有数据就立即返回错误，不等待
	//while(!USART_GetFlagStatus(dev->port, USART_FLAG_RXNE));
    if(!USART_GetFlagStatus(dev->port, USART_FLAG_RXNE)) return STD_ERR_BUFFER_UNDERFLOW;
    // 读取数据
    *ch = USART_ReceiveData(dev->port);
	return STD_ERR_OK;
}

std_err_t mcu_uart_send(mcu_uart_t* dev, const void* data, size_t len, size_t *sentlen) {
	if(!dev || !dev->port || !data || !len) { return STD_ERR_INVALID_ARG; }
	const uint8_t* bytes = (const uint8_t*)data;
    if(sentlen) *sentlen = 0;

    for(size_t i = 0; i<len; i++) {
		while(!USART_GetFlagStatus(dev->port, USART_FLAG_TXE));
		USART_SendData(dev->port, bytes[i]);
	}

	// 确保最后一个字节真正传输完成了，再返回
	// 否则，对于485驱动来说，返回后会关闭芯片的发送使能，从而导致最后一个字节发送不完！！！
	while(!USART_GetFlagStatus(dev->port, USART_FLAG_TC));
    if(sentlen) *sentlen = len;
	return STD_ERR_OK;
}

std_err_t mcu_uart_sendstr(mcu_uart_t* dev, const char* str) {
    return mcu_uart_send(dev, str, strlen(str), NULL);
}

rx_ret_t mcu_uart_receive(mcu_uart_t* dev, void* buf, size_t bufsize, size_t *rxlen, long timeout, /*long lead,*/ long interval, const char *okFlag, rx_flag_t okFlagType, const char *failFlag, rx_flag_t failFlagType) {
    if(!dev || !dev->port || !buf || !bufsize) { return RX_RET_ERROR; }

    // 清空缓冲区，以免因残留数据导致数据标志匹配错误
    memset(buf, 0, bufsize);
    // 留一个位置给尾部 '\0'
    bufsize--;

    // 同步接收数据时，应关闭接收中断，防止数据被中断服务程序读走了
    mcu_uart_rx_irq_enable(dev, false);

    uint32_t start = unios_ms_now();
    uint32_t lastByteTime = 0;
    size_t len = 0;
    char *data = (char*)buf;
    rx_ret_t ret;

	while(1) {
		if(USART_GetFlagStatus(dev->port, USART_FLAG_RXNE) != RESET) {
            // 收到数据
			data[len++] = USART_ReceiveData(dev->port);
            lastByteTime = unios_ms_now();

            // 因缓冲区满中止
            if(len >= bufsize) { ret = RX_RET_FULL; break; }
            // 因 OK 标志中止
            if(okFlag && okFlagType == RX_FLAG_STRING && strstr(data, okFlag)) { ret = RX_RET_OK; break; }
            // 因 Fail 标志中止
            if(failFlag && failFlagType == RX_FLAG_STRING && strstr(data, failFlag)) { ret = RX_RET_FAIL; break; }
        }

        // 因总超时中止
        if(timeout > 0 && (unios_ms_elapsed(start) >= timeout)) { ret = RX_RET_TIMEOUT; break; }
        // 因间隔超时中止
        if(interval > 0 && lastByteTime && (unios_ms_elapsed(lastByteTime) >= interval)) { ret = RX_RET_INTERVAL; break; }
    }

    if(rxlen) *rxlen = len;
    return ret;
}

/// 用于标准 I/O 的 UART 端口
static mcu_uart_t *_stduart = NULL;

void mcu_stduart_set(mcu_uart_t* dev) {
	_stduart = dev;
}

mcu_uart_t* mcu_stduart_get() {
	return _stduart;
}

/// 用于 console 的相关 API
static inline size_t _uart_console_send(void* dev, const void* data, size_t len) {
	size_t txlen = 0;
	mcu_uart_send((mcu_uart_t*)dev, data, len, &txlen);
	return txlen;
}

static inline void _uart_console_on_rx_char(mcu_uart_t* dev, void* cookie, uint8_t ch) {
	console_on_rx_char((console_t*)cookie, ch);
}

std_err_t mcu_uart_listen_for_console(mcu_uart_t* dev, console_t* con) {
	if(!dev || !con) { return STD_ERR_INVALID_ARG; }
	
	// 挂接 console 的发送到 UART
	con->tx = _uart_console_send; con->txcookie = dev;
	// 清空接收缓冲区
	con->rxlen = 0;
	// 挂接 UART 的接收到 console
	mcu_uart_set_rxbyte_callback(dev, _uart_console_on_rx_char, con);
	// 注册任务队列 RX 消息处理器
	unios_task_register_rxmsg_handler(con->rxmsgtype, console_on_rx_command, con);
	// 打开 UART 接收中断
	return mcu_uart_rx_irq_enable(dev, true);	
}
